from datetime import datetime, timedelta
import json
import threading

import requests
import time

from threading import Thread, Event
from flask_socketio import SocketIO, send
from flask import Flask, render_template, request
from app1 import app
from flask_restx import Namespace, Resource, fields

socketio1 = SocketIO(app, cors_allowed_origins='*')

# 创建 Flask-RESTx 命名空间
ns_websocket = Namespace('ns_websocket', description='web socket1')


@ns_websocket.route('/wstest')
class WebsocketResource(Resource):
    def get(self):
        # return render_template('index.html')
        response_data = {
            "message": {
                "result": 1,  # 请求正常
                "result_text": f"websocket test",
                "count": 0,
                "data": []
            }
        }
        return response_data, 200


# @socketio1.on('message')
# def handle_message(data):
#     ip_address = request.remote_addr  # 获取客户端 IP 地址
#     message_with_ip = {'ip': ip_address, 'message': data}
#     print(f'received message: {message_with_ip}')
#     send(message_with_ip, broadcast=True)


# 定义API请求的相关信息
BASEURL = 'http://127.0.0.1:5002'

# 告警总数，1个月的告警总数， 1周的告警总数
url_getbymultiquerytypelist = BASEURL + '/nskmsalarm/getbymultiquerytypelist'

# 虚机总数，并且统计操作系统类型的数量
url_postbyquerymachinecmdbcount = BASEURL + '/ns_machine_cmdb/postbyquerymachinecmdbcount'
url_postdashbaordmachinvaluests = BASEURL + '/ns_machine_cmdb/postdashbaordmachinvaluests'

# 按照五级告警统计数据(时间范围可以输入)
url_postdashbaordlevel = BASEURL + '/nskmsalarm/postdashbaordlevel'

# 按照app系统统计数量(时间范围可以输入)
url_postdashbaordappcount = BASEURL + '/nskmsalarm/postdashbaordappcount'

headers = {
    'accept': 'application/json',
    'Content-Type': 'application/json'
}

data_payload = {
    "source": [],
    "machine_type": [],
    "service_catalog": [],
    "app_name": [],
    "project_name": [],
    "app_abbre": [],
    "availability_level": [],
    "dr_level": [],
    "machine_name": [],
    "ip": [],
    "dmz_ip": [],
    "data_center": [],
    "network_area": [],
    "resource_pool": [],
    "host_machine": [],
    "physical_machine": [],
    "server_type": [],
    "os_level": [],
    "middleware": [],
    "status": [],
    "online_time": [],
    "run_status": [],
    "rec_date": [],
    "role_a": [],
    "role_b": [],
    "role_c": []
}

data_payload_1 = {
    "source": [],
    "machine_type": [],
    "service_catalog": [],
    "app_name": [],
    "project_name": [],
    "app_abbre": [],
    "availability_level": [],
    "dr_level": [],
    "machine_name": [],
    "ip": [],
    "dmz_ip": [],
    "data_center": [],
    "network_area": [],
    "resource_pool": [],
    "host_machine": [],
    "physical_machine": [],
    "server_type": [],
    "os_level": [],
    "middleware": [],
    "status": [],
    "online_time": [],
    "run_status": [],
    "rec_date": [],
    "role_a": [],
    "role_b": [],
    "role_c": []
}

# 操作系统种类统计 日期如不送则取默认值
os_level_payload = {
    "field_type": "os_level",
    "start_date": "2023-09-25",
    "end_date": "2024-09-25"
}

# 给与一个Dafault值，可通过传参覆盖
data_payload_2 = {
    "type": "level",
    "start_date": "2024-08-01 22:36:49",
    "end_date": "2024-09-23 22:36:49"
}

# 告警查询输入
alarm_level_payload = {
    "sys_name": [],
    "dev_addr": [],
    "repeat_times": [],
    "level": [],
    "start_date": "2024-07-25 00:38:43",
    "end_date": "2024-09-25 00:38:43"
}

START_THREAD = "启动线程"
STOP_THREAD = "停止线程"
RUNNING_THREAD = "线程运行中"

START_THREAD_1 = "MACHINE_ALL_START 1"
STOP_THREAD_1 = "MACHINE_ALL_STOP 1"
RUNNING_THREAD_1 = "MACHINE_ALL_RUNNING"

START_THREAD_2 = "ALARM_ALL_START 2"
STOP_THREAD_2 = "ALARM_ALL_STOP 2"
RUNNING_THREAD_2 = "ALARM_ALL_RUNNING"

# 请求数据指令
# 虚机总数
MACHINE_ALL = "MACHINE_ALL"
# 告警总数
ALARM_ALL = "ALARM_ALL"
# 当日告警总数
ALARM_TODAY = "ALARM_TODAY"
# 当周告警总数
ALARM_WEEK = "ALARM_WEEK"
# 当月告警总数
ALARM_MONTH = "ALARM_MONTH"
# 当日五级告警总数统计
ALARM_TODAY_LEVEL = "ALARM_TODAY_LEVEL"
# 当日排名前10应用和告警数
ALARM_TODAY_TEN = "ALARM_TODAY_TEN"

# 用于停止定时任务的事件
stop_event = Event()

stop_event1 = Event()
stop_event2 = Event()

# 用于跟踪当前是否有定时请求线程正在运行
current_thread = None
thread_lock = threading.Lock()

# 告警总数，1个月的告警总数， 1周的告警总数
# 虚机总数，并且统计操作系统类型的数量
# 按照五级告警统计数据(时间范围可以输入
# 按照app系统统计数量(时间范围可以输入)
current_thread1 = None
current_thread2 = None
current_thread3 = None
current_thread4 = None


# 定义发送请求并合并数据的函数
def send_request_and_merge(ip_address, original_message):
    try:
        # 发送 POST 请求到指定的URL
        response = requests.post(url_postbyquerymachinecmdbcount, headers=headers, data=json.dumps(data_payload))

        # 如果请求成功
        if response.status_code == 200:
            api_response_data = response.json()  # 获取请求的数据

            # 修改原数据内容
            original_message = RUNNING_THREAD

            # 将请求返回的数据合并到 message_with_ip
            message_with_ip = {
                'ip': ip_address,
                'message': original_message,
                'api_response': api_response_data  # 将API返回的数据合并
            }
            print(f'Final message with IP and API data: {message_with_ip}')

            # 发送合并后的数据到客户端（广播发送）
            # socketio1.send(message_with_ip, broadcast=True)
            socketio1.send(message_with_ip)
        else:
            print(f"Error: Received status code {response.status_code}")

    except Exception as e:
        print(f"Error occurred during API request: {e}")


# 虚机资源数量
def send_request_and_merge_1(ip_address, original_message, thread_number):
    try:
        # 发送 POST 请求到指定的URL
        response = requests.post(url_postbyquerymachinecmdbcount, headers=headers, data=json.dumps(data_payload_1))

        # 如果请求成功
        if response.status_code == 200:
            api_response_data = response.json()  # 获取请求的数据

            # 修改原数据内容
            original_message = RUNNING_THREAD_1

            # 将请求返回的数据合并到 message_with_ip
            message_with_ip = {
                'ip': ip_address,
                'message': original_message,
                'api_response': api_response_data,
                'thread_number': thread_number
            }
            print(f'Final message with IP and API data from Thread {thread_number}: {message_with_ip}')

            # 发送合并后的数据到客户端（广播发送）
            # socketio1.send(message_with_ip, broadcast=True)
            socketio1.send(message_with_ip)
        else:
            print(f"Error: Received status code {response.status_code}")

        # 发送 POST 请求到指定的URL 统计操作系统类型的数量
        response = requests.post(url_postdashbaordmachinvaluests, headers=headers, data=json.dumps(os_level_payload))

        # 如果请求成功
        if response.status_code == 200:
            api_response_data = response.json()  # 获取请求的数据

            # 修改原数据内容
            original_message = RUNNING_THREAD_1

            # 将请求返回的数据合并到 message_with_ip
            message_with_ip = {
                'ip': ip_address,
                'message': original_message,
                'api_response': api_response_data,
                'thread_number': thread_number
            }
            print(f'Final message with IP and API data from Thread {thread_number}: {message_with_ip}')

            # 发送合并后的数据到客户端（广播发送）
            # socketio1.send(message_with_ip, broadcast=True)
            socketio1.send(message_with_ip)
        else:
            print(f"Error: Received status code {response.status_code}")
    except Exception as e:
        print(f"Error occurred during API request in Thread {thread_number}: {e}")


# 告警的数量
def send_request_and_merge_2(ip_address, original_message, thread_number):
    try:
        # debug

        # 将日期字符串转换为 datetime 对象
        # 将带 'T' 的日期字符串转换为 datetime 对象
        start_date = datetime.strptime(original_message["startTime"], '%Y-%m-%d %H:%M:%S')
        end_date = datetime.strptime(original_message["endTime"], '%Y-%m-%d %H:%M:%S')

        # 将 datetime 对象格式化为不带 'T' 的字符串
        start_date_str = start_date.strftime('%Y-%m-%d %H:%M:%S')
        end_date_str = end_date.strftime('%Y-%m-%d %H:%M:%S')

        # 暂存一下 original_message 下面会被替换
        temp_start_date_str = start_date_str
        temp_end_date_str = end_date_str

        # 将转换后的日期字符串放入 payload 中
        data_payload_2["start_date"] = start_date_str
        data_payload_2["end_date"] = end_date_str
        # 发送 POST 请求到指定的URL
        response = requests.post(url_getbymultiquerytypelist, headers=headers, data=json.dumps(data_payload_2))

        # 如果请求成功
        if response.status_code == 200:
            api_response_data = response.json()  # 获取请求的数据

            # 修改原数据内容
            original_message = RUNNING_THREAD_2

            # 将请求返回的数据合并到 message_with_ip
            message_with_ip = {
                'ip': ip_address,
                'message': original_message,
                'api_response': api_response_data,
                'thread_number': thread_number
            }
            print(f'Final message with IP and API data from Thread {thread_number}: {message_with_ip}')

            # 发送合并后的数据到客户端（广播发送）
            # socketio1.send(message_with_ip, broadcast=True)
            socketio1.send(message_with_ip)
        else:
            print(f"Error: Received status code {response.status_code}")

        # 取一个月前的数据
        # 获取当前时间作为结束时间
        end_date = datetime.now()
        # 计算开始时间为当前时间的一个月前
        start_date = end_date - timedelta(days=30)

        # 将 datetime 对象格式化为不带 'T' 的字符串
        start_date_str = start_date.strftime('%Y-%m-%d %H:%M:%S')
        end_date_str = end_date.strftime('%Y-%m-%d %H:%M:%S')

        # 将转换后的日期字符串放入 payload 中
        data_payload_2["start_date"] = start_date_str
        data_payload_2["end_date"] = end_date_str

        # 发送 POST 请求到指定的URL
        response = requests.post(url_getbymultiquerytypelist, headers=headers, data=json.dumps(data_payload_2))

        # 如果请求成功
        if response.status_code == 200:
            api_response_data = response.json()  # 获取请求的数据

            # 修改原数据内容
            original_message = "one_month"

            # 将请求返回的数据合并到 message_with_ip
            message_with_ip = {
                'ip': ip_address,
                'message': original_message,
                'api_response': api_response_data,
                'thread_number': thread_number
            }
            print(f'Final message with IP and API data from Thread {thread_number}: {message_with_ip}')

            # 发送合并后的数据到客户端（广播发送）
            # socketio1.send(message_with_ip, broadcast=True)
            socketio1.send(message_with_ip)
        else:
            print(f"Error: Received status code {response.status_code}")

        # 取一周前的数据
        # 获取当前时间作为结束时间
        end_date = datetime.now()
        # 计算开始时间为当前时间的一个月前
        start_date = end_date - timedelta(days=7)

        # 将 datetime 对象格式化为不带 'T' 的字符串
        start_date_str = start_date.strftime('%Y-%m-%d %H:%M:%S')
        end_date_str = end_date.strftime('%Y-%m-%d %H:%M:%S')

        # 将转换后的日期字符串放入 payload 中
        data_payload_2["start_date"] = start_date_str
        data_payload_2["end_date"] = end_date_str

        # 发送 POST 请求到指定的URL
        response = requests.post(url_getbymultiquerytypelist, headers=headers, data=json.dumps(data_payload_2))

        # 如果请求成功
        if response.status_code == 200:
            api_response_data = response.json()  # 获取请求的数据

            # 修改原数据内容
            original_message = "one_week"

            # 将请求返回的数据合并到 message_with_ip
            message_with_ip = {
                'ip': ip_address,
                'message': original_message,
                'api_response': api_response_data,
                'thread_number': thread_number
            }
            print(f'Final message with IP and API data from Thread {thread_number}: {message_with_ip}')

            # 发送合并后的数据到客户端（广播发送）
            # socketio1.send(message_with_ip, broadcast=True)
            socketio1.send(message_with_ip)
        else:
            print(f"Error: Received status code {response.status_code}")

        # # 按照五级告警统计数据(时间范围可以输入)
        # url_postdashbaordlevel = BASEURL + '/nskmsalarm/postdashbaordlevel'

        # 从临时变量中取出日期
        alarm_level_payload["start_date"] = temp_start_date_str
        alarm_level_payload["end_date"] = temp_end_date_str
        # 发送 POST 请求到指定的URL
        response = requests.post(url_postdashbaordlevel, headers=headers, data=json.dumps(alarm_level_payload))

        # 如果请求成功
        if response.status_code == 200:
            api_response_data = response.json()  # 获取请求的数据

            # 修改原数据内容
            original_message = RUNNING_THREAD_2

            # 将请求返回的数据合并到 message_with_ip
            message_with_ip = {
                'ip': ip_address,
                'message': original_message,
                'api_response': api_response_data,
                'thread_number': thread_number
            }
            print(f'Final message with IP and API data from Thread {thread_number}: {message_with_ip}')

            # 发送合并后的数据到客户端（广播发送）
            # socketio1.send(message_with_ip, broadcast=True)
            socketio1.send(message_with_ip)
        else:
            print(f"Error: Received status code {response.status_code}")

        # 按照app系统统计数量(时间范围可以输入)
        # url_postdashbaordappcount = BASEURL + '/nskmsalarm/postdashbaordappcount'
        # 从临时变量中取出日期
        alarm_level_payload["start_date"] = temp_start_date_str
        alarm_level_payload["end_date"] = temp_end_date_str
        # 发送 POST 请求到指定的URL
        response = requests.post(url_postdashbaordappcount, headers=headers, data=json.dumps(alarm_level_payload))

        # 如果请求成功
        if response.status_code == 200:
            api_response_data = response.json()  # 获取请求的数据

            # 修改原数据内容
            original_message = RUNNING_THREAD_2

            # 将请求返回的数据合并到 message_with_ip
            message_with_ip = {
                'ip': ip_address,
                'message': original_message,
                'api_response': api_response_data,
                'thread_number': thread_number
            }
            print(f'Final message with IP and API data from Thread {thread_number}: {message_with_ip}')

            # 发送合并后的数据到客户端（广播发送）
            # socketio1.send(message_with_ip, broadcast=True)
            socketio1.send(message_with_ip)
        else:
            print(f"Error: Received status code {response.status_code}")

    except Exception as e:
        print(f"Error occurred during API request in Thread {thread_number}: {e}")


# 定时发送请求的函数
def periodic_request(ip_address, original_message):
    while not stop_event.is_set():
        # print("debug2")
        send_request_and_merge(ip_address, original_message)
        time.sleep(10)  # 每10秒发送一次请求


def periodic_request_1(ip_address, original_message, stop_event, thread_number):
    while not stop_event.is_set():
        if thread_number == 1:
            send_request_and_merge_1(ip_address, original_message, thread_number)
            time.sleep(10)  # 每10秒发送一次请求
        if thread_number == 2:
            send_request_and_merge_2(ip_address, original_message, thread_number)
            time.sleep(10)  # 每10秒发送一次请求


# 关键修改：
# current_thread 全局变量：用于跟踪当前正在执行的定时任务线程。
# thread_lock 锁：确保多线程环境下的线程检查和启动操作是线程安全的。
# is_alive() 方法：用来检查线程是否还在运行。如果线程已经结束或尚未启动，则可以启动新的线程；否则，什么也不做。
# 工作原理：
# 每次收到 message 事件时，首先检查当前是否已经有一个线程在执行定时任务。
# 如果没有线程运行或者线程已经结束，那么启动一个新的线程来执行任务。
# 如果线程已经在运行，则不启动新的线程，避免多个线程同时执行任务。
# 这种方式可以确保同时只有一个线程在运行定时请求逻辑。


# 启动线程
def start_thread(ip_address, data):
    global current_thread

    with thread_lock:
        # 如果当前没有线程，或者线程已经结束，启动新的线程
        if current_thread is None or not current_thread.is_alive():
            stop_event.clear()  # 确保停止事件没有被设置
            current_thread = threading.Thread(target=periodic_request, args=(ip_address, data))
            current_thread.start()
            print("Thread started.")
        else:
            print("Thread is already running.")
            # 发送合并后的数据到客户端（广播发送）
            # socketio1.send(message_with_ip, broadcast=True)
            message_with_ip = {
                'ip': ip_address,
                'message': "Thread is already running."
            }
            socketio1.send(message_with_ip)


def start_thread_1(ip_address, data, thread_number):
    global current_thread1, current_thread2

    with thread_lock:
        if thread_number == 1:
            if current_thread1 is None or not current_thread1.is_alive():
                stop_event1.clear()
                current_thread1 = threading.Thread(target=periodic_request_1, args=(ip_address, data, stop_event1, 1))
                current_thread1.start()
                print("Thread 1 started.")
            else:
                print("Thread 1 is already running.")
        elif thread_number == 2:
            if current_thread2 is None or not current_thread2.is_alive():
                stop_event2.clear()
                current_thread2 = threading.Thread(target=periodic_request_1, args=(ip_address, data, stop_event2, 2))
                current_thread2.start()
                print("Thread 2 started.")
            else:
                print("Thread 2 is already running.")


# 停止线程
def stop_thread(ip_address, data):
    global current_thread

    with thread_lock:
        if current_thread is not None and current_thread.is_alive():
            stop_event.set()  # 触发停止事件，结束线程
            current_thread.join()  # 等待线程结束
            current_thread = None
            print("Thread stopped.")
        else:
            print("No active thread to stop.")
            message_with_ip = {
                'ip': ip_address,
                'message': "No active thread to stop."
            }
            socketio1.send(message_with_ip)


def stop_thread_1(ip_address, data, thread_number):
    global current_thread1, current_thread2

    with thread_lock:
        if thread_number == 1:
            if current_thread1 is not None and current_thread1.is_alive():
                stop_event1.set()
                current_thread1.join()
                current_thread1 = None
                print("Thread 1 stopped.")
            else:
                print("No active thread 1 to stop.")
        elif thread_number == 2:
            if current_thread2 is not None and current_thread2.is_alive():
                stop_event2.set()
                current_thread2.join()
                current_thread2 = None
                print("Thread 2 stopped.")
            else:
                print("No active thread 2 to stop.")


# SocketIO 处理消息事件
@socketio1.on('message')
def handle_message(data):
    ip_address = request.remote_addr  # 获取客户端 IP 地址
    print(f'Received message from IP: {ip_address} , {data}')

    # 获取当前时间并格式化
    current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')

    if data == START_THREAD:
        promptdata = data
        start_thread(ip_address, data)
    elif data == STOP_THREAD:
        promptdata = data
        stop_thread(ip_address, data)
    else:
        print("命令不正确")
        promptdata = "命令不正确"

    # 如果需要立即响应，发送初始信息
    # message_with_ip = {'ip': ip_address, 'message': promptdata}
    # 拼接 message_with_ip，并加上当前时间
    message_with_ip = {
        'ip': ip_address,
        'message': f"{promptdata} - {current_time}"  # 在 message 中拼接当前时间
    }
    send(message_with_ip, broadcast=True)  # 如果需要立即响应，发送初始信息


def parse_thread_command(data):
    parts = data.split()
    if len(parts) != 2:
        raise ValueError("命令格式不正确。正确格式：'启动线程 1' 或 '停止线程 2'")

    try:
        thread_number = int(parts[1])
    except ValueError:
        raise ValueError("线程号必须是一个数字")

    return parts[0], thread_number


@socketio1.on('message1')
def handle_message_1(data):
    ip_address = request.remote_addr
    print(f'Received message from IP: {ip_address} , {data}')
    current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')

    try:
        command, thread_number = parse_thread_command(data)
        if command == START_THREAD_1.split()[0]:
            promptdata = f"{START_THREAD_1.split()[0]} {thread_number}"
            start_thread_1(ip_address, data, thread_number)
        elif command == STOP_THREAD_1.split()[0]:
            promptdata = f"{STOP_THREAD_1.split()[0]} {thread_number}"
            stop_thread_1(ip_address, data, thread_number)
        elif command == START_THREAD_2.split()[0]:
            promptdata = f"{START_THREAD_2.split()[0]} {thread_number}"
            start_thread_1(ip_address, data, thread_number)
        elif command == STOP_THREAD_2.split()[0]:
            promptdata = f"{STOP_THREAD_2.split()[0]} {thread_number}"
            stop_thread_1(ip_address, data, thread_number)
        else:
            raise ValueError("未知命令")
    except ValueError as e:
        print(f"命令错误：{str(e)}")
        promptdata = f"命令错误：{str(e)}"

    message_with_ip = {
        'ip': ip_address,
        'message': f"{promptdata} - {current_time}"
    }
    send(message_with_ip, broadcast=True)


@socketio1.on('message_with_time')
def handle_message_with_ip(data):
    ip_address = request.remote_addr  # 获取客户端 IP 地址
    print(f'Received message from IP: {ip_address} , {data}')

    # 获取当前时间并格式化
    current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')

    # if data == START_THREAD:
    #     promptdata = data
    #     start_thread(ip_address, data)
    # elif data == STOP_THREAD:
    #     promptdata = data
    #     stop_thread()
    # else:
    #     print("命令不正确")
    #     promptdata = "命令不正确"
    if data["text"] == START_THREAD:
        promptdata = data["text"]
        start_thread(ip_address, data["text"])
    elif data["text"] == STOP_THREAD:
        promptdata = data["text"]
        stop_thread(ip_address, data)
    else:
        print("命令不正确")
        promptdata = "命令不正确"

    # 如果需要立即响应，发送初始信息
    # message_with_ip = {'ip': ip_address, 'message': promptdata}
    # 拼接 message_with_ip，并加上当前时间
    message_with_ip = {
        'ip': ip_address,
        'message': f"{promptdata} - {current_time}"  # 在 message 中拼接当前时间
    }
    send(message_with_ip, broadcast=True)  # 如果需要立即响应，发送初始信息


@socketio1.on('message_with_time1')
def handle_message_with_ip_1(data):
    ip_address = request.remote_addr
    print(f'Received message from IP: {ip_address} , {data}')
    current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')

    try:
        command, thread_number = parse_thread_command(data["text"])
        if command == START_THREAD_1.split()[0]:
            promptdata = f"{START_THREAD_1.split()[0]} {thread_number}"
            start_thread_1(ip_address, data, thread_number)
        elif command == STOP_THREAD_1.split()[0]:
            promptdata = f"{STOP_THREAD_1.split()[0]} {thread_number}"
            stop_thread_1(ip_address, data, thread_number)
        elif command == START_THREAD_2.split()[0]:
            promptdata = f"{START_THREAD_2.split()[0]} {thread_number}"
            start_thread_1(ip_address, data, thread_number)
        elif command == STOP_THREAD_2.split()[0]:
            promptdata = f"{STOP_THREAD_2.split()[0]} {thread_number}"
            stop_thread_1(ip_address, data, thread_number)
        else:
            raise ValueError("未知命令")
    except ValueError as e:
        print(f"命令错误：{str(e)}")
        promptdata = f"命令错误：{str(e)}"

    message_with_ip = {
        'ip': ip_address,
        'message': f"{promptdata} - {current_time}"
    }
    send(message_with_ip, broadcast=True)


# 在应用关闭时停止定时任务
@socketio1.on('disconnect')
def handle_disconnect():
    stop_event.set()


@socketio1.on('disconnect')
def handle_disconnect_1():
    stop_event1.set()
    stop_event2.set()
